#include <gtk/gtk.h>/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sqlite3.h>
#include "img_table.h"
#include "scroll_pane.h"
#include "tagline.h"
#include "db_access.h"
#include "text_vector_utils.h"
#include "interface.h"

void attach_imgtable_controls(GtkContainer *window,
        GtkWidget *,
        GtkWidget *,
        GtkWidget *,
        GtkWidget *);
void rebind_img_table(GtkWidget *new_img_table);
void reinit_img_table();

void move_tag(TagLine *from, TagLine *to,
        GtkObject *tag_button, gpointer *tag_name);


//имя файла с базой данных
const char *DATABASE = "database.db";

//соединение с базой данных
sqlite3 *db_connect;

//главное окно
GtkWidget *main_window;

//таблица картинок в главном окне
GtkWidget *img_table;
//список возможных действий
GtkWidget *actions_menu;
//вертикальный список тегов
TagLine *vtag_line;
//горизонтальный список тегов
TagLine *htag_line;


/* Инициализация ------------------------------------------------------------*/

//инициализация соединенияя с БД
int db_init() {
    int rc;
    rc = sqlite3_open(DATABASE, &db_connect);
    if(rc == SQLITE_OK) {
        create_tables_if_not_exist(db_connect);
    }

    return rc;
}

//инициализирует главное окно программы
void main_window_init() {
    main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_signal_connect_object(GTK_OBJECT(main_window),
            "delete_event",
            GTK_SIGNAL_FUNC(delete_main_window_event),
            NULL);
    gtk_widget_show(main_window);
}

//обработчик клика по тегу в вертикальном списке тегов
//перемещает тег из вертикального списка в горизонтальный
void move_to_horizontal_tagline(GtkObject *tag_button, gpointer tag_name) {
    move_tag(vtag_line, htag_line, tag_button, tag_name);
    reinit_img_table();
}

//инициализирует список тегов
void vertical_tagline_init() {
    char **tags;

    vtag_line = new_vtag_line(move_to_horizontal_tagline);
    get_all_tags(db_connect, &tags);
    add_tags_to_tagline(vtag_line, tags);
    free_vector(tags);
}

//обработчик клика по тегу в горизонтальном списке тегов
//перемещает тег из горизонтального списка в вертикальный
void move_to_vertical_tagline(GtkObject *tag_button, gpointer tag_name) {
    move_tag(htag_line, vtag_line, tag_button, tag_name);
    reinit_img_table();
}

//инициализирует список тегов
void horizontal_tagline_init() {
    htag_line = new_htag_line(move_to_vertical_tagline);
}

//инициализирует строку с кнопками выбора действий
void actions_menu_init() {
    const struct _Action {
        const char *name;
        void (*action)(GtkObject *, gpointer *);
    } action_table[] = {
        {"add file", add_file},
        {"add tag", add_tag},
        {"delete tag", delete_tag_handler},
        {"images without tags", show_img_without_tags}
    };
    int action_num = sizeof(action_table) / sizeof(action_table[0]);
    
    GtkWidget *button;

    int i;

    actions_menu = gtk_hbutton_box_new();
    gtk_button_box_set_layout(GTK_BUTTON_BOX(actions_menu), GTK_BUTTONBOX_START);
    for(i = 0; i < action_num; i++) {
        button = gtk_button_new_with_label((gchar *) action_table[i].name);
        gtk_signal_connect(GTK_OBJECT(button),
                "clicked",
                GTK_SIGNAL_FUNC(action_table[i].action),
                NULL);

        gtk_container_add(GTK_CONTAINER(actions_menu), button);
        gtk_widget_show(button);
    }
    gtk_widget_show(actions_menu);
}


/* Повторная инициализация --------------------------------------------------*/

//проводит повторную инициализацию таблицы картинок
void reinit_img_table() {
    GtkWidget *new_img_table;
    GtkWidget *wrapped_new_img_table;

    char **paths;
    get_paths_with_tags(db_connect, &paths, htag_line->tag_vector);

    new_img_table = img_preview_table_new_from_files(paths, edit_callback);
    gtk_widget_show(new_img_table);
    wrapped_new_img_table = wrap_with_scroll_pane(new_img_table);
    gtk_widget_show(wrapped_new_img_table);
    rebind_img_table(wrapped_new_img_table);

    free_vector_with_elems(paths);
}

//проводит повторную инициализацию таблицы картинок
//отображая превью на картинки не отмеченные тегами
void reinit_img_table_without_tags() {
    GtkWidget *new_img_table;
    GtkWidget *wrapped_new_img_table;

    char **paths;
    get_paths_without_tags(db_connect, &paths);

    new_img_table = img_preview_table_new_from_files(paths, edit_callback);
    gtk_widget_show(new_img_table);
    wrapped_new_img_table = wrap_with_scroll_pane(new_img_table);
    gtk_widget_show(wrapped_new_img_table);
    rebind_img_table(wrapped_new_img_table);

    free_vector_with_elems(paths);
}

//повторно инициализирует теглайны
void reinit_taglines() {
    free_vector_with_elems(vtag_line->tag_vector);
    gtk_widget_destroy(vtag_line->tag_line);
    free(vtag_line);

    free_vector_with_elems(htag_line->tag_vector);
    gtk_widget_destroy(htag_line->tag_line);
    free(htag_line);

    vertical_tagline_init();
    horizontal_tagline_init();
    
    rebind_vertical_tagline(vtag_line->tag_line);
    rebind_horizontal_tagline(htag_line->tag_line);
}


/* добавление и замена элементов главного окна -------------------------------*/

//количество строк и столбцов таблицы по которой выравниваются элементы
//прикрепляемые к главному окну
const int NROWS = 16;
const int NCOLS = 16;

//прикрепляет панель выбора тегов, список выбранных тегов и
//область с картинками к контейнеру window
void attach_imgtable_controls(GtkContainer *window,
        GtkWidget *actions_menu,
        GtkWidget *img_table,
        GtkWidget *vertical_tagline,
        GtkWidget *horizontal_tagline) {

    const int SPACING = 10;

    GtkTable *table = GTK_TABLE(gtk_table_new(NROWS, NCOLS, TRUE));
    gtk_table_set_row_spacings(table, SPACING);
    gtk_table_set_col_spacings(table, SPACING);

    gtk_table_attach_defaults(table, actions_menu, 0, NCOLS - 1, 0, 1);
    gtk_table_attach_defaults(table, img_table, 0, NCOLS - 1, 1, NROWS - 1);
    gtk_table_attach_defaults(table, vertical_tagline, NCOLS - 1, NCOLS, 0, NROWS - 1);
    gtk_table_attach_defaults(table, horizontal_tagline, 0, NCOLS, NROWS - 1, NROWS);

    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(table));
    gtk_widget_show(GTK_WIDGET(table));
}

//заменить вертикальный список тегов в главном окне не new_vertical_tagline
void rebind_vertical_tagline(GtkWidget *new_vertical_tagline) {
    gtk_table_attach_defaults(GTK_TABLE(gtk_bin_get_child(GTK_BIN(main_window))),
            new_vertical_tagline,
            NCOLS - 1,
            NCOLS,
            0,
            NROWS - 1);
}

//заменить горизонтальный список тегов в главном окне не new_vertical_tagline
void rebind_horizontal_tagline(GtkWidget *new_horizontal_tagline) {
    gtk_table_attach_defaults(GTK_TABLE(gtk_bin_get_child(GTK_BIN(main_window))),
            new_horizontal_tagline,
            0,
            NCOLS,
            NROWS - 1,
            NROWS);
}

//заменить таблицу картинок в главном окне не new_vertical_tagline
void rebind_img_table(GtkWidget *new_img_table) {
    gtk_table_attach_defaults(GTK_TABLE(gtk_bin_get_child(GTK_BIN(main_window))),
            new_img_table,
            0,
            NCOLS - 1,
            1,
            NROWS - 1);
}


/* Редактирование списка тегов ----------------------------------------------*/

//вспомогательные теглайны для диалога редактирования тегов
TagLine *path_tags;
TagLine *other_tags;

//перемещает тег из path_tags в other_tags
void move_to_other_tags(GtkObject *tag_button, gpointer tag_name) {
    move_tag(path_tags, other_tags, tag_button, tag_name);
}

//перемещает тег из other_tags в path_tags
void move_to_path_tags(GtkObject *tag_button, gpointer tag_name) {
    move_tag(other_tags, path_tags, tag_button, tag_name);
}

//отображает диалог изменения списка тегов связанных с путём path
//и изменяет этот список в базе
void edit_tags_dialog(const char *path) {
    int i;
    GtkWidget *dialog;

    //теги которыми отмечен путь
    char **path_tags_vector;
    //имеющиеся в базе теги, которыми он не отмечен
    char **other_tags_vector;
    get_tags_for_path(db_connect, &path_tags_vector, path);
    get_all_tags(db_connect, &other_tags_vector);
    for(i = 0; path_tags_vector[i] != NULL; i++) {
        free_elem_from_text_vector(other_tags_vector,
                NULL,
                path_tags_vector[i]);
    }

    path_tags = new_htag_line(move_to_other_tags);
    add_tags_to_tagline(path_tags, path_tags_vector);
    other_tags = new_vtag_line(move_to_path_tags);
    add_tags_to_tagline(other_tags, other_tags_vector);
    
    dialog = gtk_dialog_new_with_buttons("edit tags",
            GTK_WINDOW(main_window),
            GTK_DIALOG_DESTROY_WITH_PARENT,
            GTK_STOCK_OK,
            GTK_RESPONSE_OK,
            NULL);
    g_signal_connect_swapped(dialog,
            "response",
            G_CALLBACK(gtk_widget_destroy),
            dialog);
    attach_imgtable_controls(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
            gtk_label_new("select tags for image"),
            wrap_with_scroll_pane(gtk_image_new_from_file(path)),
            other_tags->tag_line,
            path_tags->tag_line);

    gtk_widget_show_all(dialog);
    gtk_dialog_run(GTK_DIALOG(dialog));

    //удаляем все связи тегов с данным путём
    delete_all_links_with_path(db_connect, path);
    //добавляем связи с выбранными пользователем тегами
    add_path_tags_links(db_connect, path, path_tags->tag_vector);

    free_vector(path_tags->tag_vector);
    free_vector(other_tags->tag_vector);
    free(path_tags);
    free(other_tags);
    free_vector_with_elems(path_tags_vector);
    free_vector_with_elems(other_tags_vector);

    reinit_img_table();
}

void edit_callback(GtkWidget *widget, GdkEvent *event, gpointer path) {
    edit_tags_dialog((const char *) path);
}

/* Добавление нового тега в базу --------------------------------------------*/

//добавляет новый тег в базу
void add_tag(GtkObject *o, gpointer *p) {
    GtkWidget *gtk_entry = gtk_entry_new();
    GtkWidget *dialog = gtk_dialog_new_with_buttons("new tag",
            GTK_WINDOW(main_window),
            GTK_DIALOG_DESTROY_WITH_PARENT,
            GTK_STOCK_OK,
            GTK_RESPONSE_NONE,
            NULL);
    
    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
            gtk_entry);
    gtk_widget_show_all(dialog);
    gtk_dialog_run(GTK_DIALOG(dialog));
    
    if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_entry))) > 0) {
        add_tag_if_not_exists(db_connect, gtk_entry_get_text(GTK_ENTRY(gtk_entry)));
    }

    gtk_widget_destroy(dialog);
    reinit_taglines();
}


/* Удаление тега из базы ----------------------------------------------------*/

//удаляет тег из базы и теглайна выбора удаляемого тега
void tag_deleter(GtkObject *tag_button, gpointer tag_name) {
    if(delete_tag(db_connect, (const char *) tag_name) != SQLITE_OK) {
        db_error(db_connect);
    }
    gtk_widget_destroy(GTK_WIDGET(tag_button));
}

void delete_tag_handler(GtkObject *o, gpointer *p) {
    char **all_tags;

    GtkWidget *deleting_dialog =
        gtk_dialog_new_with_buttons("select tag for deleting",
                GTK_WINDOW(main_window),
                GTK_DIALOG_DESTROY_WITH_PARENT,
                GTK_STOCK_CLOSE,
                GTK_RESPONSE_NONE,
                NULL);

    TagLine *selection_line = new_htag_line(tag_deleter);

    get_all_tags(db_connect, &all_tags);
    add_tags_to_tagline(selection_line, all_tags);

    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(deleting_dialog)->vbox),
            selection_line->tag_line);
    gtk_widget_show_all(deleting_dialog);
    
    gtk_dialog_run(GTK_DIALOG(deleting_dialog));
    gtk_widget_destroy(deleting_dialog);

    reinit_taglines();
    free_vector_with_elems(selection_line->tag_vector);
    free(selection_line);
}

/* Добавление пути в базу ---------------------------------------------------*/

//отображает интерфейс для доюавления пути к файлу в базу
void add_file(GtkObject *o, gpointer *p) {
    char *img_path;

    GtkWidget *file_select_dialog =
        gtk_file_chooser_dialog_new("add image",
                GTK_WINDOW(main_window),
                GTK_FILE_CHOOSER_ACTION_OPEN,
                GTK_STOCK_CANCEL,
                GTK_RESPONSE_CANCEL,
                GTK_STOCK_OPEN,
                GTK_RESPONSE_ACCEPT,
                NULL);

    //получаем путь к файлу
    if(gtk_dialog_run(GTK_DIALOG(file_select_dialog)) == GTK_RESPONSE_ACCEPT) {
        img_path =
            gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_select_dialog));
        
        gtk_widget_destroy(file_select_dialog);

        //добавляем его в базу
        add_path_if_not_exists(db_connect, img_path);
        //переходим в режим редактирования тегов для данного пути
        edit_tags_dialog(img_path);

        g_free(img_path);
    } else {
        gtk_widget_destroy(file_select_dialog);
    }
    
    reinit_img_table();
}


/* Отображение путей без тегов ----------------------------------------------*/

//отображает в таблице картинок картинки не отмеченные тегами
void show_img_without_tags(GtkObject *o, gpointer *p) {
    reinit_taglines();
    reinit_img_table_without_tags();
}


/* Вспомогательные функции --------------------------------------------------*/

//завершает программу при закрытии главного окна
void delete_main_window_event(GtkObject *object) {
    gtk_main_quit();
}

//перемещает тег отображаемый при помощи tag_button с именем tag_name
//из теглайна from в теглайн to
void move_tag(TagLine *from, TagLine *to,
        GtkObject *tag_button, gpointer *tag_name) {
    
    //удаляем тег из теглайна from
    gtk_container_remove(GTK_CONTAINER(from->tag_line),
            GTK_WIDGET(tag_button));

    //добавляем тег в теглайн to
    add_to_tagline(to, (char *) tag_name);

    //удаляем тег из вектора имён тегов теглайна from
    free_elem_from_text_vector(from->tag_vector,
            &(from->tag_count),
            (char *) tag_name);

}



int main(int argc, char *argv[]) {
    GtkWidget *scrollable_imb_table;
    char **paths;
    if(db_init() != SQLITE_OK) {
        db_error(db_connect);
    }

    gtk_init(&argc, &argv);
    main_window_init();
    vertical_tagline_init();
    horizontal_tagline_init();
    actions_menu_init();

    get_paths_with_tags(db_connect, &paths, htag_line->tag_vector);
    img_table = img_preview_table_new_from_files(paths, edit_callback);
    gtk_widget_show(img_table);

    scrollable_imb_table = wrap_with_scroll_pane(img_table);
    gtk_widget_show(scrollable_imb_table);
    
    attach_imgtable_controls(GTK_CONTAINER(main_window),
            actions_menu,
            scrollable_imb_table,
            vtag_line->tag_line,
            htag_line->tag_line);

    gtk_widget_show(img_table);

    gtk_main();
    sqlite3_close(db_connect);
    
    return 0;
}

